#include <iostream>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "bglProgram.h"
#include "bglTexture2D.h"
#include "bglCamera.h"
#include "bglWidget.h"

class BaseWidget : public BGLWidget
{
private:
	unsigned int m_VBO; //顶点缓冲区对象
	unsigned int m_VAO; //顶点数组对象
	unsigned int m_lightVAO; //顶点数组对象
	
	BGLProgram m_lightProgram;
	BGLProgram m_lampProgram;

	BGLCamera m_camera;

	glm::mat4 m_model = glm::mat4(1.0f);

	bool m_leftIsPress; //判断鼠标左键是否按下
	float m_lastX;   //上一帧鼠标的x位置
	float m_lastY;   //上一帧鼠标的y位置

public:
	BaseWidget() : BGLWidget()
	{
		m_leftIsPress = false;
	}

	~BaseWidget()
	{

	}

	virtual void Init() 
	{
		//6个面 x 每个面有2个三角形组成 x 每个三角形有3个顶点
		float vertices[] = {
			-0.5f, -0.5f, -0.5f,
			 0.5f, -0.5f, -0.5f,
			 0.5f,  0.5f, -0.5f,
			 0.5f,  0.5f, -0.5f,
			-0.5f,  0.5f, -0.5f,
			-0.5f, -0.5f, -0.5f,

			-0.5f, -0.5f,  0.5f,
			 0.5f, -0.5f,  0.5f,
			 0.5f,  0.5f,  0.5f,
			 0.5f,  0.5f,  0.5f,
			-0.5f,  0.5f,  0.5f,
			-0.5f, -0.5f,  0.5f,

			-0.5f,  0.5f,  0.5f,
			-0.5f,  0.5f, -0.5f,
			-0.5f, -0.5f, -0.5f,
			-0.5f, -0.5f, -0.5f,
			-0.5f, -0.5f,  0.5f,
			-0.5f,  0.5f,  0.5f,

			0.5f,  0.5f,  0.5f,
			0.5f,  0.5f, -0.5f,
			0.5f, -0.5f, -0.5f,
			0.5f, -0.5f, -0.5f,
			0.5f, -0.5f,  0.5f,
			0.5f,  0.5f,  0.5f,

			-0.5f, -0.5f, -0.5f,
			 0.5f, -0.5f, -0.5f,
			 0.5f, -0.5f,  0.5f,
			 0.5f, -0.5f,  0.5f,
			-0.5f, -0.5f,  0.5f,
			-0.5f, -0.5f, -0.5f,

			-0.5f,  0.5f, -0.5f,
			 0.5f,  0.5f, -0.5f,
			 0.5f,  0.5f,  0.5f,
			 0.5f,  0.5f,  0.5f,
			-0.5f,  0.5f,  0.5f,
			-0.5f,  0.5f, -0.5f
		};

		glGenVertexArrays(1, &m_VAO); //创建顶点数组对象
		glGenVertexArrays(1, &m_lightVAO);
		
		//设置顶点属性的属性
		
		glGenBuffers(1, &m_VBO);  //创建顶点缓冲区
		glBindBuffer(GL_ARRAY_BUFFER, m_VBO); //绑定顶点缓冲区
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //GL_STATIC_DRAW:数据不会或几乎不会改变。

		glBindVertexArray(m_VAO); //绑定顶点数组
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0); //启用0号顶点属性

		glBindBuffer(GL_ARRAY_BUFFER, m_VBO); //绑定顶点缓冲区
		glBindVertexArray(m_lightVAO);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0); //启用0号顶点属性

		m_lightProgram.createProgramFromFile("./data/shaders/12_light/light.vs", "./data/shaders/12_light/light.fs"); //创建shader program
		m_lampProgram.createProgramFromFile("./data/shaders/12_light/lamp.vs", "./data/shaders/12_light/lamp.fs"); //创建shader program
		glEnable(GL_DEPTH_TEST);
		//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //绘制模式
		//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//

		int screenWidth;
		int screenHeight;
		this->GetWindowSize(&screenWidth, &screenHeight);
		m_camera.InitCamera(screenWidth, screenHeight);
	}

	virtual void Render()
	{
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


		m_lightProgram.begin();

	  	m_lightProgram.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
        m_lightProgram.setVec3("lightColor",  1.0f, 1.0f, 1.0f);

		glm::mat4 MVP = m_camera.GetMVP();
		m_lightProgram.setMat4("MVP", MVP);

		glBindVertexArray(m_lightVAO);
		glDrawArrays(GL_TRIANGLES, 0, 36);  //总共有36个顶点。

		m_lightProgram.end();


		m_lampProgram.begin();

		m_model = glm::mat4(1.0f);
		m_model = glm::translate(m_model, glm::vec3(4, -1, -2));
		m_lampProgram.setMat4("MVP", MVP * m_model);

		glBindVertexArray(m_VAO);
		glDrawArrays(GL_TRIANGLES, 0, 36);  //总共有36个顶点。
		
		m_lampProgram.end();
	}

	virtual void FramebufferSizeCallback(GLFWwindow* window, int width, int height)
	{
		if(width != 0 && height != 0)
		{
			glViewport(0, 0, width, height);
			m_camera.SetScreenWidth(width);
			m_camera.SetScreenHeight(height);
		}
		
	}

	virtual void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
	{
		glm::vec3 position = m_camera.GetPosition();

		std::cout << yoffset << std::endl;

		if (yoffset > 0)
			position.z *= 0.8f;
		else
			position.z *= 1.2f;

		m_camera.SetPosition(position);
	}

	virtual void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
	{
		glm::vec3 target = m_camera.GetTargetPosition();

		if (key == GLFW_KEY_W && (action == GLFW_REPEAT || action == GLFW_PRESS))
		{
			target.y -= 0.2f;
		}	
		if (key == GLFW_KEY_S && (action == GLFW_REPEAT || action == GLFW_PRESS))
		{
			target.y += 0.2f;
		}
			
		if (key == GLFW_KEY_A && (action == GLFW_REPEAT || action == GLFW_PRESS))
		{
			target.x += 0.2f;
		}
			
		if (key == GLFW_KEY_D && (action == GLFW_REPEAT || action == GLFW_PRESS))
		{
			target.x -= 0.2f;
		}
			
		m_camera.SetTargetPosition(target);
	}

	virtual void MousebuttonCallback(GLFWwindow* window, int button, int action, int mods)
	{
		if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
		{
			m_leftIsPress = true;
		}
		if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE)
		{
			m_leftIsPress = false;
		}
	}

	virtual void CursorPositionCallback(GLFWwindow * window, double xpos, double ypos)
	{
		if (m_leftIsPress)
		{
			float offsetX = xpos - m_lastX;
			float offsetY = ypos - m_lastY;

			glm::vec3 rotate(offsetY, offsetX, 0);
			m_camera.RotationOfWorld(rotate);
		}

		m_lastX = xpos;
		m_lastY = ypos;	
	}
}; 



int main() {
	
	BaseWidget widget;
	widget.Run();

	return 0;
}